package cn.qingfeng.demo.transaction.springboot.declarative.transactionSimple.service.impl;

import cn.qingfeng.demo.transaction.springboot.common.entity.User;
import cn.qingfeng.demo.transaction.springboot.common.mapper.UserMapper;
import cn.qingfeng.demo.transaction.springboot.declarative.transactionSimple.service.TransactionalDemoService;
import cn.qingfeng.demo.transaction.springboot.declarative.transactionSimple.service.TransactionalDemoService2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Transactional//可以用在类上或方法上，都用时以方法上的为准
public class TransactionalDemoServiceImpl implements TransactionalDemoService {//这里不要忘记实现接口，否则controller中注入不了。
    //注入用户Mapper
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private TransactionalDemoService2 transactionalDemoService2;


    /**
     * 内部调用
     * <p>
     * 加了Transactional注解就相当于在方法的开头建立数据库连接，在方法的末尾commit。
     * 方法中的任何DML操作都不会立刻提交，而是放到方法结束时一块提交。
     * <p>
     * 内部调用会使被调用的方法上的事务注解失效。
     * 规律就是经过ioc调用的事务注解生效，不经过ioc调用直接内部调用的事务注解失效。
     */
    @Override
    public void addUser() {
        User user = new User("外层", UUID.randomUUID().toString());
        userMapper.add(user);
        System.out.println("outter向数据库中插入了User----" + user);

        try {
            addUser2();
        } catch (RuntimeException e) {
            e.printStackTrace();
        }

        int a = 1 / 0;
    }

    /**
     * 外部调用
     *
     * @param user
     */
    @Override
    public void addUser1(User user) {
        userMapper.add(user);//正常提交
        System.out.println("向数据库中插入了User----" + user);

        try {
            transactionalDemoService2.addUser2();//回滚。这里addUser2上的事务Transactional注解有效，Transactional注解只有在外部调用时才会生效。
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 用来测试内部调用对事务的影响
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void addUser2() {
        User user = new User("内层", UUID.randomUUID().toString());
        userMapper.add(user);
        System.out.println("inner向数据库中插入了User----" + user);

//        int a = 1 / 0;//制造异常，验证事务回滚
    }

    /**
     * 测试数据库的事务隔离级别
     */
    @Transactional(isolation = Isolation.DEFAULT)
    @Override
    public void testReadCommittedWrite() throws InterruptedException {
        User user = new User(12, "aaa", UUID.randomUUID().toString());
        userMapper.update(user);
        System.out.println("将数据库中id为" + user.getId() + "的数据修改为user: " + user + " ，等待1分钟后再提交");
        TimeUnit.MINUTES.sleep(1);
    }
}
